package models

import (
	"fmt"
	"strconv"
	"strings"

	"time"

	"errors"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

//评论表
type Comments struct {
	Id         int
	Uid        int       `orm:"index"` //用户id
	BookId     int       `orm:"index"` //文档项目id
	Content    string    //评论内容
	TimeCreate time.Time //评论时间
	Status     int8      //  审核状态; 0，待审核，1 通过，-1 不通过
}

//评分表
type Score struct {
	Id         int
	BookId     int
	Uid        int
	Score      int //评分
	TimeCreate time.Time
}

// 多字段唯一键
func (this *Score) TableUnique() [][]string {
	return [][]string{
		[]string{"Uid", "BookId"},
	}
}

//评论内容
type BookCommentsResult struct {
	Id                  int                   `json:"id"`
	Uid                 int                   `json:"uid"`
	Score               int                   `json:"score"`
	Avatar              string                `json:"avatar"`
	Account             string                `json:"account"`
	Nickname            string                `json:"nickname"`
	BookId              int                   `json:"book_id"`
	BookName            string                `json:"book_name"`
	Identify            string                `json:"identify"`
	Content             string                `json:"content"`
	Status              int8                  `json:"status"`
	TimeCreate          time.Time             `json:"created_at"` //评论时间
	ReplyCommentsResult []ReplyCommentsResult `json:"replycommentsresult"`
}

func NewComments() *Comments {
	return &Comments{}
}

func (this *ReplyComments) TableName() string {
	return "replycomments"
}

func (this *Comments) SetCommentStatus(id, status int) (err error) {
	_, err = orm.NewOrm().QueryTable(this).Filter("id", id).Update(orm.Params{"status": status})
	return
}

// 获取可显示的评论内容
func (this *Comments) Comments(p, listRows, bookId int, status ...int) (comments []BookCommentsResult, err error) {
	sql := `select c.id,c.content,s.score,c.uid,c.status,c.time_create,m.avatar,m.nickname,m.account,b.book_id,b.book_name,b.identify from md_comments c left join md_members m on m.member_id=c.uid left join md_score s on s.uid=c.uid and s.book_id=c.book_id left join md_books b on b.book_id = c.book_id %v order by c.id desc limit %v offset %v`
	whereStr := ""
	whereSlice := []string{"true"}
	if bookId > 0 {
		whereSlice = append(whereSlice, "c.book_id = "+strconv.Itoa(bookId))
	}
	if len(status) > 0 {
		whereSlice = append(whereSlice, "c.status = "+strconv.Itoa(status[0]))
	}

	if len(whereSlice) > 0 {
		whereStr = " where " + strings.Join(whereSlice, " and ")
	}

	sql = fmt.Sprintf(sql, whereStr, listRows, (p-1)*listRows)
	_, err = orm.NewOrm().Raw(sql).QueryRows(&comments)
	if err == nil {

		for k, v := range comments {
			var replycommentsresult []ReplyCommentsResult
			sql = ""
			sql = `SELECT
			a.id AS id,
			a.comment_id AS commentid  ,
			a.reply_type AS replytype,
			a.reply_id as replyid,
			a.from_uid as fromuid,
			c.nickname AS fromname,
			c.avatar AS fromavatar,
			c.account AS fromaccount,
			a.to_uid as touid,
			d.nickname AS toname,
			d.account AS toaccount,
			a.content as content,
			a.status as status,
			a.time_create as timecreate
			FROM
			md_replycomments AS a
			INNER JOIN md_comments AS b ON a.comment_id = b.id AND a.comment_id = b.id
			INNER JOIN md_members AS c ON a.from_uid = c.member_id
			INNER JOIN md_members AS d ON a.to_uid = d.member_id AND a.to_uid = d.member_id
			WHERE
			a.comment_id =` + strconv.Itoa(v.Id) + `   ORDER BY a.time_create`
			_, err = orm.NewOrm().Raw(sql).QueryRows(&replycommentsresult)
			comments[k].ReplyCommentsResult = replycommentsresult
		}
	}
	return
}

type CommentCount struct {
	Id     int
	BookId int
	Cnt    int
}

// 清空评论
func (this *Comments) ClearComments(uid int) {
	var (
		comments  []CommentCount
		cid       []interface{}
		bookId    []interface{}
		bookIdMap = make(map[int]int)
	)
	o := orm.NewOrm()
	sql := "select count(id) cnt,id,book_id from md_comments where uid = ? group by book_id"
	o.Raw(sql, uid).QueryRows(&comments)
	fmt.Printf("%+v", comments)
	if len(comments) > 0 {
		for _, comment := range comments {
			cid = append(cid, comment.Id)
			bookId = append(bookId, comment.BookId)
			bookIdMap[comment.BookId] = comment.Cnt
		}
		var err error
		o.Begin()
		defer func() {
			if err != nil {
				beego.Error(err)
				o.Rollback()
			} else {
				o.Commit()
			}
		}()
		_, err = o.QueryTable(this).Filter("book_id__in", bookId...).Delete()
		if err != nil {
			return
		}
		sqlUpdate := "update md_books set cnt_comment = cnt_comment - ? where cnt_comment> ? and book_id = ?"
		for bid, cnt := range bookIdMap {
			if _, err = o.Raw(sqlUpdate, cnt, cnt-1, bid).Exec(); err != nil {
				return
			}
		}
	}
}

// 删除评论
func (this *Comments) DeleteComment(id int) {
	m := &Comments{}
	o := orm.NewOrm()
	o.QueryTable(m).Filter("id", id).One(m, "book_id")
	if m.BookId > 0 {
		o.QueryTable(m).Filter("id", id).Delete()
		sql := "update md_books set cnt_comment = cnt_comment - 1 where cnt_comment > 0 and book_id = ?"
		_, err := o.Raw(sql, m.BookId).Exec()
		if err != nil {
			beego.Error(err.Error())
		}
	}
}

func (this *Comments) Count(bookId int, status ...int) (int64, error) {
	query := orm.NewOrm().QueryTable(this)
	if bookId > 0 {
		query = query.Filter("book_id", bookId)
	}
	if len(status) > 0 {
		query = query.Filter("status", status[0])
	}
	return query.Count()
}

//评分内容
type BookScoresResult struct {
	Avatar     string    `json:"avatar"`
	Nickname   string    `json:"nickname"`
	Score      string    `json:"score"`
	TimeCreate time.Time `json:"time_create"` //评论时间
}

//获取评分内容
func (this *Score) BookScores(p, listRows, bookId int) (scores []BookScoresResult, err error) {
	sql := `select s.score,s.time_create,m.avatar,m.nickname from md_score s left join md_members m on m.member_id=s.uid where s.book_id=? order by s.id desc limit %v offset %v`
	sql = fmt.Sprintf(sql, listRows, (p-1)*listRows)
	_, err = orm.NewOrm().Raw(sql, bookId).QueryRows(&scores)
	return
}

//查询用户对文档的评分
func (this *Score) BookScoreByUid(uid, bookId interface{}) int {
	var score Score
	orm.NewOrm().QueryTable("md_score").Filter("uid", uid).Filter("book_id", bookId).One(&score, "score")
	return score.Score
}

//添加评论内容

//添加评分
//score的值只能是1-5，然后需要对score x 10，50则表示5.0分
func (this *Score) AddScore(uid, bookId, score int) (err error) {
	//查询评分是否已存在
	o := orm.NewOrm()
	var scoreObj = Score{Uid: uid, BookId: bookId}
	o.Read(&scoreObj, "uid", "book_id")
	if scoreObj.Id > 0 { //评分已存在
		err = errors.New("您已给当前文档打过分了")
		return
	}

	// 评分不存在，添加评分记录
	score = score * 10
	scoreObj.Score = score
	scoreObj.TimeCreate = time.Now()
	o.Insert(&scoreObj)
	if scoreObj.Id > 0 { //评分添加成功，更行当前书籍项目的评分
		//评分人数+1
		var book = Book{BookId: bookId}
		o.Read(&book, "book_id")
		if book.CntScore == 0 {
			book.CntScore = 1
			book.Score = 0
		} else {
			book.CntScore = book.CntScore + 1
		}
		book.Score = (book.Score*(book.CntScore-1) + score) / book.CntScore
		_, err = o.Update(&book, "cnt_score", "score")
		if err != nil {
			beego.Error(err.Error())
			err = errors.New("评分失败，内部错误")
		}
	}
	return
}

//添加评论
func (this *Comments) AddComments(uid, bookId int, content string) (err error) {
	var comment Comments
	var status int8
	commentmoderation := beego.AppConfig.DefaultBool("CommentModeration", true)
	if commentmoderation {
		status = 0
	} else {
		status = 1
	}
	//查询该用户现有的评论
	second := beego.AppConfig.DefaultInt("CommentInterval", 60)
	now := time.Now()
	o := orm.NewOrm()
	o.QueryTable("md_comments").Filter("uid", uid).Filter("TimeCreate__gt", now.Add(-time.Duration(second)*time.Second)).OrderBy("-Id").One(&comment, "Id")
	if comment.Id > 0 {
		return fmt.Errorf("您距离上次发表评论时间小于 %v 秒，请歇会儿再发。", second)
	}

	var comments = Comments{
		Uid:        uid,
		BookId:     bookId,
		Content:    content,
		Status:     status,
		TimeCreate: now,
	}

	if _, err = o.Insert(&comments); err != nil {
		beego.Error(err.Error())
		err = errors.New("发表评论失败")
		return
	}
	// 项目被评论数量量+1
	SetIncreAndDecre("md_books", "cnt_comment", fmt.Sprintf("book_id=%v", bookId), true)
	return
}

//回复表
type ReplyComments struct {
	Id         int       `orm:"column(id);pk"`
	Commentid  int       `orm:"column(comment_id)"`
	Replyid    int       `orm:"column(reply_id)"`
	Replytype  string    `orm:"column(reply_type)"`
	Content    string    `orm:"column(content)"`
	Fromuid    int       `orm:"column(from_uid)"`
	Touid      int       `orm:"column(to_uid)"`
	Timecreate time.Time `orm:"column(time_create)"`
	Status     int8      `orm:"column(status)"`
}

//回复内容
//reply_type：表示回复的类型，因为回复可以是针对评论的回复(comment)，
//也可以是针对回复的回复(reply)， 通过这个字段来区分两种情景。
//reply_id：表示回复目标的id，如果reply_type是comment的话，
//那么reply_id＝commit_id，如果reply_type是reply的话，这表示这条回复的父回复。
type ReplyCommentsResult struct {
	Id          int       `orm:"column(id);"json:"id"`
	Commentid   int       `orm:"column(commentid);"json:"commentid"` //评论id
	Replytype   string    `orm:"column(replytype);"json:"replytype"` //回复类型
	Replyid     int       `orm:"column(replyid);"json:"replyid"`     //回复目标id
	Fromuid     int       `orm:"column(fromuid);"json:"fromuid"`     //回复用户id
	Fromname    string    `orm:"column(fromname);"json:"fromname"`
	FromAvatar  string    `orm:"column(fromavatar);"json:"fromavatar"`
	FromAccount string    `orm:"column(fromaccount);"json:"fromaccount"`
	Touid       int       `orm:"column(touid);"json:"touid"` //目标用户id
	Toname      string    `orm:"column(toname);"json:"toname"`
	ToAccount   string    `orm:"column(toaccount);"json:"toaccount"`
	Content     string    `orm:"column(content);"json:"content"`
	Status      int8      `orm:"column(status);"json:"status"`
	TimeCreate  time.Time `orm:"column(timecreate);"json:"created_at"` //评论时间
}

//添加回复
func (this *ReplyComments) AddReply(uid, commentid, replyid int, replytype string, content string, touid int) (err error) {
	var replycomment ReplyComments

	//查询该用户现有的评论
	second := beego.AppConfig.DefaultInt("CommentInterval", 60)
	now := time.Now()
	o := orm.NewOrm()
	o.QueryTable("md_replycomments").Filter("Replyid", uid).Filter("TimeCreate__gt", now.Add(-time.Duration(second)*time.Second)).OrderBy("-Id").One(&replycomment, "Id")
	if replycomment.Id > 0 {
		return fmt.Errorf("您距离上次发表评论时间小于 %v 秒，请歇会儿再发。", second)
	}

	var replycomments = ReplyComments{
		Commentid:  commentid,
		Replyid:    replyid,
		Replytype:  replytype,
		Content:    content,
		Fromuid:    uid,
		Touid:      touid,
		Timecreate: now,
		Status:     1,
	}

	if _, err = o.Insert(&replycomments); err != nil {
		beego.Error(err.Error())
		err = errors.New("回复评论失败")
		return
	}

	return
}

func (this *ReplyComments) DelReply(uid, id int, replytype string) (err error) {
	switch replytype {
	//如果删除的是评论
	case "comment":
		//合法性检查，该评论id是否由uid创建
		o := orm.NewOrm()
		n, _ := o.QueryTable("md_comments").Filter("uid", uid).Filter("id", id).Count()
		if n > 0 {
			//删除回复
			sql1 := "DELETE FROM md_replycomments WHERE comment_id = ?"
			if _, err = o.Raw(sql1, id).Exec(); err != nil {
				err = errors.New("删除失败")
				return
			}
			var comment Comments
			comment.DeleteComment(id)
			return
		}
		err = errors.New("删除失败")
		return
	case "reply":
		o := orm.NewOrm()
		//合法性检查，该评论id是否由uid创建
		n, _ := o.QueryTable("md_replycomments").Filter("from_uid", uid).Filter("id", id).Count()
		if n > 0 {
			//删除该回复下的所有子回复
			sql2 := `DELETE FROM	md_replycomments WHERE	id IN 
			(SELECT	id  as delid FROM
				(SELECT	t1.id,IF
				( find_in_set( reply_id, @pids ) > 0, @pids := concat( @pids, ',', id ), 0 ) AS ischild 
			FROM
				( SELECT id, reply_id FROM md_replycomments t WHERE t.STATUS = 1 ORDER BY reply_id, id ) t1,
				( SELECT @pids := ? ) t2 
				) t3 
			WHERE
				ischild != 0)`
			if _, err = o.Raw(sql2, id).Exec(); err != nil {
				err = errors.New("删除子回复失败")
				return
			}
			//删除该回复
			if _, err = o.QueryTable("md_replycomments").Filter("id", id).Delete(); err != nil {
				err = errors.New("删除回复失败")
				return
			}
			return
		}
		err = errors.New("删除失败")
		return
	default:
		err = errors.New("删除失败")
		return
	}

}
